package com.gitee.grower.util

import org.bukkit.Location
import org.bukkit.block.Block
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta
import org.bukkit.potion.PotionEffect
import taboolib.common.util.asList
import taboolib.common5.Coerce
import taboolib.common5.Demand.Companion.toDemand
import taboolib.library.configuration.ConfigurationSection
import taboolib.library.reflex.Reflex.Companion.setProperty
import taboolib.library.xseries.XBlock
import taboolib.library.xseries.XMaterial
import taboolib.module.configuration.Configuration
import taboolib.module.nms.MinecraftVersion
import taboolib.platform.type.BukkitProxyEvent
import taboolib.platform.util.modifyMeta

/**
 * 将任意 [Map] 或 [Configuration] 转换为 [Map<String, Any?>]
 *
 * @return [Map<String, Any?>]
 */
fun Any?.asMap(): Map<String, Any?> = when (this) {
    is Map<*, *> -> entries.associate { it.key.toString() to it.value }
    is ConfigurationSection -> getValues(false)
    else -> emptyMap()
}

/**
 * 将对象转换为整型
 *
 * @param def 默认值
 * @return [Int]
 */
fun Any?.asInt(def: Int = 0): Int {
    return Coerce.toInteger(this ?: def)
}

/**
 * 将对象转换为浮点型
 *
 * @param def 默认值
 * @return [Double]
 */
fun Any?.asDouble(def: Double = 0.0): Double {
    return Coerce.toDouble(this ?: def)
}

/**
 * 判定材质是否为方块
 *
 * @param block 材质
 * @return [Boolean]
 */
fun XMaterial.isBlock(block: Block): Boolean {
    return XBlock.isSimilar(block, this) && (MinecraftVersion.majorLegacy >= 11300 || block.data == data)
}

/**
 * 替换字符串中的变量
 *
 * @param vars 变量
 * @return [String]
 */
fun String.replace(vararg vars: Pair<String, Any>): String {
    var r = this
    vars.forEach { r = r.replace("[\\[{]${it.first}[]}]".toRegex(), it.second.toString()) }
    return r
}

fun String.replace(vararg key: String, rep: Any): String {
    var r = this
    key.forEach { r = r.replace("[\\[{]${it}[]}]".toRegex(), rep.toString()) }
    return r
}

fun String.startsWith(vararg prefix: String): Boolean {
    return prefix.any { startsWith(it) }
}

fun String.substringAfter(vararg morePrefix: String): String {
    return substringAfter(morePrefix.firstOrNull { startsWith(it) } ?: return this)
}

fun String.contains(vararg value: String): Boolean {
    return value.any { indexOf(it) != -1 }
}

fun BukkitProxyEvent.callIfFailed(): Boolean {
    return !call()
}

fun <V> ConfigurationSection.mapSection(transform: (ConfigurationSection) -> V): Map<String, V> {
    return getKeys(false).associateWith { transform(getConfigurationSection(it)!!) }
}

fun <V> ConfigurationSection.mapSection(node: String, transform: (ConfigurationSection) -> V): Map<String, V> {
    return getConfigurationSection(node)?.mapSection(transform) ?: emptyMap()
}

fun ConfigurationSection.getString(vararg path: String): String? {
    path.forEach {
        val r = getString(it)
        if (r != null) return r
    }
    return null
}

fun ConfigurationSection.list(path: String): MutableList<String> {
    return get(path)?.asList()?.toMutableList() ?: arrayListOf()
}

fun <T> ConfigurationSection.mapListAs(path: String, transform: (Map<String, Any?>) -> T): MutableList<T> {
    return getMapList(path).map { transform(it.asMap()) }.toMutableList()
}

fun <K, T> ConfigurationSection.sectionAs(path: String, kf: (String) -> K, transform: (K, Any) -> T): MutableList<T> {
    return getConfigurationSection(path)?.getValues(false)?.mapKeys { kf(it.key) }?.map { transform(it.key, it.value!!) }?.toMutableList() ?: arrayListOf()
}

fun List<String>.flatLines(): List<String> {
    return flatMap { it.lines() }
}

fun List<String>.trim(): List<String> {
    return map { it.trim() }
}

fun <T, R> T.to(transform: (T) -> R): R {
    return transform(this)
}

fun Any?.asListOrString(): List<String> {
    return this?.asList() ?: emptyList()
}

fun <T> List<String>.mapAs(partition: String = "",transform: (List<String>) -> T) : List<T> {
    return this.map { it.mapAs(partition,transform) }
}

fun <T> String.mapAs(partition: String = " ",transform: (List<String>) -> T) : T {
    val split = this.split(partition)
    return transform(split)
}

@Suppress("UNCHECKED_CAST")
fun Any?.asListOrInt() : List<Int> {
    return when(this) {
        is Collection<*> -> map { it.asInt() }
        is Array<*> -> map { it.asInt() }
        is Int -> listOf(this)
        is Double -> listOf(this.asInt())
        else -> emptyList()
    }
}
